package com.db.utils.okhttp;

import android.net.Uri;
import android.text.TextUtils;
import cn.hutool.core.text.UnicodeUtil;
import com.db.utils.IpInfo;
import com.db.utils.LogUtil;
import com.db.utils.Util;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.*;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.BufferedHttpEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.*;
import org.apache.http.impl.conn.DefaultProxyRoutePlanner;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.*;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HttpClientUtil {

    //private static Log logger = LogFactory.getLog(HttpClientUtil.class);
    private static final int retryTimes = 3;
    private static final Log log = LogFactory.getLog(HttpClientUtil.class);

    private HttpClientUtil() {
    }

    public static String doGet(String url, Map<String, String> params) {

        // 创建Httpclient对象
        CloseableHttpClient httpClient = getHttpClient(url, null);
//        CloseableHttpClient httpClient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (params != null) {
                for (String key : params.keySet()) {
                    builder.addParameter(key, params.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);

/*            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectionRequestTimeout(1500)
                    .setSocketTimeout(1500) // 服务端相应超时
                    .setConnectTimeout(3000).build(); // 建立socket链接超时时间
            httpGet.setConfig(requestConfig);*/

            // 执行请求
            response = httpClient.execute(httpGet);
            // 判断返回状态是否为200
            int responseCode = response.getStatusLine().getStatusCode();
            if (responseCode == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            //e.printStackTrace();
            //System.out.println("#url Exception: " +e.toString() +" " +url);
        } finally {
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static CloseableHttpResponse doGet(String url, Map<String, String> params, Map<String, String> headers, IpInfo.DataBean proxy) {
        CloseableHttpClient httpClient = getHttpClient(url, proxy);
        CloseableHttpResponse response = null;

        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (params != null) {
                for (String key : params.keySet()) {
                    builder.addParameter(key, params.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);
            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpGet.addHeader(key, headers.get(key));
                }
            }

//            if (proxy != null) {
//                // 2024/7/16 新代理尝试, ppfly
//                httpGet.addHeader("Connection", "close");
//                // 手动添加 Proxy Authorization头
//                String auth = proxy.getUsername() + ":" + proxy.getPassword();
//                byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(StandardCharsets.ISO_8859_1));
//                String authHeader = "Basic " + new String(encodedAuth);
//                httpGet.addHeader("Proxy-Authorization", authHeader);
//            }

            LogUtil.logApp("doGet", "GET请求URL：" + httpGet.getURI());

            // 执行请求
            response = httpClient.execute(httpGet);
            // 判断返回状态是否为200
//            int responseCode = response.getStatusLine().getStatusCode();
//            if (responseCode == 200) {
//                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
//            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return response;
    }

    public static String getEntity(CloseableHttpResponse response) {
        String responseEntity = "";

        if (response == null) {
            return responseEntity;
        }

        try {
            int responseCode = response.getStatusLine().getStatusCode();
            LogUtil.logApp("getEntity", "responseCode: " + responseCode);
            if (responseCode == 200) {
//                responseEntity = EntityUtils.toString(response.getEntity(), "UTF-8");
                HttpEntity entity = new BufferedHttpEntity(response.getEntity());
                responseEntity = EntityUtils.toString(entity, "UTF-8");
            } else {
                LogUtil.logApp("getEntity", "entity: " + EntityUtils.toString(response.getEntity(), "UTF-8"));
            }
        } catch (MalformedChunkCodingException e) {
            // 分块被截断，服务器/网络问题
            LogUtil.logApp("getEntity", "chunked 提前结束");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return responseEntity;
    }

    /**
     * Post请求
     *
     * @param url
     * @param params
     * @param headers
     * @param ipData
     * @return
     */
    public static String doPost(String url, Map<String, String> params, Map<String, String> headers, IpInfo.DataBean ipData) {
        CloseableHttpClient httpClient = getHttpClient(url, ipData);
        CloseableHttpResponse response = null;
        String resultString = "";

        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpPost.addHeader(key, headers.get(key));
                }
            }

            // 创建参数列表
            if (params != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : params.keySet()) {
                    paramList.add(new BasicNameValuePair(key, params.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            // 打印响应状态
            //logger.info(response.getStatusLine().getStatusCode());
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

    public static String doPostRawData(String url, String rawData) {
        String respStr = "";

        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 创建POST请求
            HttpPost httpPost = new HttpPost(url);

            // 设置请求体为RAW格式
            StringEntity entity = new StringEntity(rawData);
            httpPost.setEntity(entity);

            // 设置Content-Type
            httpPost.setHeader("Content-Type", "application/json");

            // 执行请求
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                int statusCode = response.getStatusLine().getStatusCode();
                if (statusCode == 200) {
                    // 响应内容
                    respStr = EntityUtils.toString(response.getEntity());
                    respStr = "ok";
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return respStr;
    }

    public static String doPostJson(String url, String json, String token_header) throws Exception {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建请求内容
            httpPost.setHeader("HTTP Method", "POST");
            httpPost.setHeader("Connection", "Keep-Alive");
            httpPost.setHeader("Content-Type", "application/json;charset=utf-8");
            if (!TextUtils.isEmpty(token_header)) {
                httpPost.setHeader("x-authentication-token", token_header);
            }

            StringEntity entity = new StringEntity(json);

            entity.setContentType("application/json;charset=utf-8");
            httpPost.setEntity(entity);

            // 执行http请求
            response = httpClient.execute(httpPost);
            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return resultString;
    }

    static ConnectionKeepAliveStrategy kaStrategy = null;
    static PoolingHttpClientConnectionManager cm = null;

    static {
        cm = new PoolingHttpClientConnectionManager();
        // 连接池最大连接数
        cm.setMaxTotal(5000);
        // 单条链路最大连接数（一个ip+一个端口 是一个链路）
        cm.setDefaultMaxPerRoute(50);
        // 指定某条链路的最大连接数
        kaStrategy = new DefaultConnectionKeepAliveStrategy() {
            @Override
            public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
                long keepAlive = super.getKeepAliveDuration(response, context);
                if (keepAlive == -1) {
//                    keepAlive = 60 * 1000;
                    keepAlive = 30 * 1000;
                }
                return keepAlive;
            }
        };
    }

    public static CloseableHttpClient getHttpClient(String url, IpInfo.DataBean ipData) {
        return getHttpClient(url, ipData, true);
    }

    public static CloseableHttpClient getHttpClient(String url, IpInfo.DataBean ipData, boolean isRedirects) {
        String proxyHost = null;
        String proxyPort = null;
        String proxyUserName = null;
        String proxyPassword = null;
        String proxyProtocol = "http"; //socks http;Proxy.Type.SOCKS: Proxy.Type.HTTP
//        String proxyProtocol = "socks"; //socks http;Proxy.Type.SOCKS: Proxy.Type.HTTP

        if (url != null && (url.contains("://192.") || url.contains("://127."))) {
            ipData = null;
        }

        // 信任所有证书
        SSLContext sslContext = null;
        try {
            sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
                        @Override
                        public boolean isTrusted(X509Certificate[] chain, String authType) {
                            return true;
                        }
                    })
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
        }

//        SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(
//                sslContext,
//                new String[]{"TLSv1", "TLSv1.1", "TLSv1.2"},
//                null,
//                NoopHostnameVerifier.INSTANCE);
        SSLConnectionSocketFactory sslSF = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
        HttpClientBuilder httpClientBuilder = HttpClients.custom().setSSLSocketFactory(sslSF);

        if (ipData != null) {
            try {
                proxyHost = ipData.getProxyIp();
                proxyPort = String.valueOf(ipData.getProxyPort());
                proxyUserName = ipData.getUsername();
                proxyPassword = ipData.getPassword();
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (proxyHost != null) {
                HttpHost proxyHttp = new HttpHost(proxyHost, Integer.parseInt(proxyPort), proxyProtocol);
                DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxyHttp);
                httpClientBuilder.setRoutePlanner(routePlanner);
//                httpClientBuilder = HttpClients.custom().setSSLSocketFactory(sslSF).setRoutePlanner(routePlanner);

                if (proxyUserName == null) {
                    proxyUserName = "";
                }
                if (proxyPassword == null) {
                    proxyPassword = "";
                }
                //Client credentials
                if (proxyUserName != null && proxyUserName.length() > 1) {
                    CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                    credentialsProvider.setCredentials(
                            new AuthScope(proxyHttp),
                            new UsernamePasswordCredentials(proxyUserName, proxyPassword));
                    httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                }
            }
        }

        RequestConfig config = RequestConfig.custom()
                .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
                .setConnectionRequestTimeout(20_000) // 从连接池里“借”连接的最大等待时间
                .setSocketTimeout(45_000) // 读写数据超时时长
                .setConnectTimeout(20_000) // 建立TCP三次握手超时时长
                .build();
        if (!isRedirects) {
            config = RequestConfig.custom()
                    .setRedirectsEnabled(false)
                    .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
                    .build();
            // httpClientBuilder.setDefaultRequestConfig(config);
            // httpClientBuilder.setRedirectStrategy(new DefaultRedirectStrategy());
        }
        // httpClientBuilder.evictIdleConnections(5, TimeUnit.SECONDS); // 关闭空闲链接
        httpClientBuilder.setRetryHandler(new MyHttpRequestRetryHandler());
        // httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler());

        // 设置禁止重定向
        CloseableHttpClient httpClient = httpClientBuilder
                .setRedirectStrategy(new DefaultRedirectStrategy() {
                    @Override
                    public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context) {
                        return false;
                    }
                })
                .setDefaultRequestConfig(config)
                // 设置cm、kaStrategy会经常出现Connection pool shut down异常
//                .setConnectionManager(cm)
//                .setKeepAliveStrategy(kaStrategy)
//                .useSystemProperties()
                .disableAutomaticRetries()
                .build();

        return httpClient;
    }

    private static class MyHttpRequestRetryHandler implements HttpRequestRetryHandler {

        @Override
        public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
            //System.out.println(Thread.currentThread().getName()+" retryRequest: " + executionCount + " "+exception.toString());
            if (executionCount > retryTimes) {
                return false;
            }
            if (exception instanceof SSLException) {
                return false;
            }
            if (exception instanceof InterruptedIOException
                    || exception instanceof NoHttpResponseException) {
                // Timeout or 服务端断开连接
                return true;
            }
            // Unknown host
            if (exception instanceof UnknownHostException) {
                return false;
            }
            // SSL handshake exception
            if (exception instanceof SSLException) {
                return false;
            }

            final HttpClientContext clientContext = HttpClientContext.adapt(context);
            final HttpRequest request = clientContext.getRequest();
            boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
            if (idempotent) {
                // Retry if the request is considered idempotent
                return true;
            }
            return false;
        }
    }

    /**
     * 获取符合下载特征的重定向URL
     *
     * @param uuid
     * @param taskId
     * @param url
     * @param params
     * @param headers
     * @param ipData
     * @param campaign
     * @param adgroup
     * @param creative
     * @param callback
     * @return 符合条件的重定向URL
     */
    public static String getReferrerNew(String uuid, int taskId, String gaid,
                                        String url, Map<String, String> params,
                                        Map<String, String> headers, IpInfo.DataBean ipData,
                                        String campaign, String adgroup,
                                        String creative, String callback) {

        // 2024/5/24 trafficguard有校验idfa格式
        if (url.contains("click.trafficguard.ai")) {
            url = url.replace("{idfa}", gaid);
        }

        String msgDetail = "uuid:" + uuid + ", taskId:" + taskId + ", ";

        CloseableHttpClient httpClient = getHttpClient(url, ipData, false);
        CloseableHttpResponse response = null;

        String resultString = "";
        try {
            url = change(url, campaign, adgroup, creative, callback);
            url = url.replace("|", "%7C");
            url = url.replace("{", "%7B");
            url = url.replace("}", "%7D");
            url = url.replace(" ", "%20");
            // 2025/3/18新增
            url = url.replace("<", "%3C");
            url = url.replace(">", "%3E");

            // 创建Uri
            URIBuilder builder = new URIBuilder(url);
            if (params != null) {
                for (String key : params.keySet()) {
                    builder.addParameter(key, params.get(key));
                }
            }

            // 创建http GET请求
            URI uri = builder.build();
            HttpGet httpGet = new HttpGet(uri);
            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpGet.addHeader(key, headers.get(key));
                }
            }
            // ppfly、kkoip代理，处理异常：The target server failed to respond
            httpGet.setHeader("Connection", "close");

            // 执行请求
            if (ipData != null) {
                LogUtil.logApp("GetReferrer", msgDetail + "url:" + url + ", proxyIp:" + ipData.getIp() + ", iso:" + ipData.getIso());
            }

            response = httpClient.execute(httpGet);
            // 判断返回状态是否为200
            String url302 = null;
            int responseCode = response.getStatusLine().getStatusCode();
            LogUtil.logApp("GetReferrer", msgDetail + "StatusCode:" + responseCode);

            if (responseCode == 301 || responseCode == 302 || responseCode == 307) {
                url302 = response.getHeaders("Location")[0].getValue();
                if (url302 == null || url302.length() < 2) {
                    // 临时重定向和永久重定向location的大小写有区分
                    url302 = response.getHeaders("location")[0].getValue();
                }
                if (!(url302.startsWith("http://") || url302.startsWith("https://")
                        || url302.startsWith("market:") || url302.startsWith("https://apps.apple.com"))) {
                    //某些时候会省略host，只返回后面的path，所以需要补全url
                    URL originalUrl = new URL(url);
                    url302 = originalUrl.getProtocol() + "://" + originalUrl.getHost() + ":" + originalUrl.getPort() + url302;
                }
            } else if (responseCode == 200 || responseCode == 202 || responseCode == 400) {
                try {
                    resultString = EntityUtils.toString(response.getEntity(), "utf-8");
//                    LogUtil.logApp("GetReferrer", msgDetail + "StatusCode:" + responseCode + ", resultString:" + resultString);

                    if (resultString != null) {
                        // 获取window.location.replace对应的链接
                        url302 = getWindowLocationReplaceUrl(resultString);
                        if ("".equals(url302)) {
                            if (resultString.contains("url=")) {
                                resultString = resultString.substring(resultString.indexOf("url=") + 4);
                                url302 = resultString.substring(0, resultString.indexOf("\""));
                            } else if (resultString.contains("URL=")) {
                                resultString = resultString.substring(resultString.indexOf("URL=") + 4);
                                url302 = resultString.substring(0, resultString.indexOf("\""));
                            } else if (resultString.contains("href=")) {
                                resultString = resultString.substring(resultString.indexOf("href=") + 6);
                                url302 = resultString.substring(0, resultString.indexOf("\""));
                            } else if (resultString.contains("market://")) {
                                JsonObject jsonObject = JsonParser.parseString(resultString).getAsJsonObject();
                                url302 = jsonObject.get("url").getAsString();
                            }
                        }
                    }
                    LogUtil.logApp("GetReferrer", msgDetail + "url302:" + url302);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if (url302 == null || url302.isEmpty()) {
                LogUtil.logApp("GetReferrer", "url302 is empty, " + msgDetail + "url:" + url302 + ", statusCode:" + responseCode);
                return url;//可能异常了
            }

            if (url302.startsWith("market:")
                    || (!url302.contains("app.adjust.com") && url302.endsWith(".apk"))
//                    || url302.contains("referrer=")
                    || url302.contains("adjust_referrer=")
                    || url302.contains(".apk?")
                    || url302.startsWith("https://play.google.com")
                    || url302.startsWith("https://view.adjust.com")
                    || url302.startsWith("https://apps.apple.com")
                    || url302.startsWith("https://itunes.apple.com")
                    || url302.startsWith("https://apkpure.net/")
                    || url302.contains("trip.com")
                    || url302.contains("m.fomo7.com")
                    || url302.contains("https://lv77.co")
                    || url302.startsWith("https://www.gochatapp.net")
            ) {
                LogUtil.logApp("GetReferrer", "URL重定向成功, " + msgDetail + "url:" + url302);
                return url302;
            }
            return getReferrerNew(uuid, taskId, gaid, url302, null, headers, ipData, campaign, adgroup, creative, callback);
        } catch (Exception e) {
            LogUtil.logApp("GetReferrer Exception", "请求异常, " + msgDetail + "url:" + url + ", Exception Message:" + e.getMessage());
            e.printStackTrace();
        } finally {
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        LogUtil.logApp("GetReferrer End", msgDetail
                + "url:" + url + ", responseString:" + resultString
                + ", Ip:" + ipData.getIp() + ", proxyIp:" + ipData.getProxyIp()
                + ", iso:" + ipData.getIso() + ", mcc:" + ipData.getMcc());

        return url;
    }

    private static String change(String url, String campaign, String adgroup, String creative, String callback) throws MalformedURLException, UnsupportedEncodingException {
        if (url.contains(".adjust.") && (!isNull(campaign) || !isNull(adgroup) || !isNull(creative) || !isNull(callback))) {
            StringBuffer sb = new StringBuffer();
            URL u = new URL(url);
            String query = u.getQuery();
            //u.getProtocol()+"://"+u.getHost()+u.getPath()+"?"
            sb.append(u.getProtocol()).append("://").append(u.getHost()).append(u.getPath()).append("?");
            String[] querys = query.split("&");
            for (int i = 0; i < querys.length; i++) {
                String[] item = querys[i].split("=");
                sb.append(item[0]).append("=");
                if (item[0].equals("campaign") && !isNull(campaign)) {
                    //sb.append(campaign);
                    appendItem(sb, item, campaign);
                } else if (item[0].equals("adgroup") && !isNull(adgroup)) {
                    //sb.append(adgroup);
                    appendItem(sb, item, adgroup);
                } else if (item[0].equals("creative") && !isNull(creative)) {
                    //sb.append(creative);
                    appendItem(sb, item, creative);
                } else if (item[0].contains("_callback") && !isNull(callback)) {
                    if (item.length > 1) {
                        //System.out.println("_callback_0:  "+item[0]+"="+item[1]);
                        String tmp = item[1];
                        if (tmp.length() > 15) {
                            int index = tmp.indexOf("%2F", 15);//第三个斜杠
                            if (index > 0) {
                                tmp = tmp.substring(index);
                                sb.append(URLEncoder.encode(callback, Util.ENCODING)).append(tmp);
                            }
                        }
                    }
                } else {
                    if (item.length > 1) {
                        sb.append(item[1]);
                    }
                }

                if (i < querys.length) {
                    sb.append("&");
                }
            }
            url = sb.toString();
        }
        return url;
    }

    public static void appendItem(StringBuffer sb, String[] item, String value) {
        if (item.length > 1) {
            String oldValue = item[1];
            String regex = "\\{([^}]*)\\}";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(oldValue);
            if (matcher.find()) {//替换部分
                String newValue = matcher.replaceFirst(value);
                sb.append(newValue);
            } else {//全部替换
                sb.append(value);
            }
        } else {//可能之前没有值
            sb.append(value);
        }
    }

    private static boolean isNull(Object obj) {
        return Util.isNull(obj);
    }

    /**
     * 获取响应内容中的重定向URL
     *
     * @param responseContent 响应内容
     * @return 重定向URL
     */
    private static String getWindowLocationReplaceUrl(String responseContent) {
        Pattern pattern;
        Matcher matcher;
        String redirectUrl = "";

        try {
            // RegEx：重定向URL
            String[] redirectRegex = {
                    "window.location.replace\\(\"(https?://[^\"]*?)\"\\)",
                    "window.location.replace\\(\"(.*?)\"\\)",
                    "window.location.href\\s*=\\s*['\"](.+?)['\"]"
            };

            for (String regex : redirectRegex) {
                pattern = Pattern.compile(regex);
                matcher = pattern.matcher(responseContent);
                if (matcher.find()) {
                    redirectUrl = matcher.group(1);
                    // Unicode转字符串，如：\u003D转成=
                    redirectUrl = UnicodeUtil.toString(redirectUrl);
                    break;
                }
            }
        } catch (Exception e) {
            LogUtil.logApp("WindowLocationReplaceUrl", "response:" + responseContent + ", Exception:" + e.getMessage());
            e.printStackTrace();
        }

        LogUtil.logApp("WindowLocationReplaceUrl", "window.location.replace url:" + redirectUrl);
        return redirectUrl;
    }

    public static String getReferrerValue(String uuid, String url) {
        String referrer = "";

        if (url.contains(".apk?") || url.endsWith(".apk")) {
            return referrer;
        }

        if (url.contains("referrer=")) {
            try {
                Uri uri = Uri.parse(url);
                referrer = uri.getQueryParameter("referrer");
                LogUtil.logApp("getReferrerValue", "uuid:" + uuid + ", 获取Referrer：" + referrer);
            } catch (Exception e) {
                LogUtil.logApp("getReferrerValue", "uuid:" + uuid + ", 获取Referrer异常：url=" + url);
                e.printStackTrace();
            }
        }

        return referrer;
    }

    public static void main(String[] args) {
        String tmpStr = "\n" +
                "<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>Proceed to the app store</title>\n" +
                "    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n" +
                "    <meta name=\"viewport\" content=\"width=device-width initial-scale=1\">\n" +
                "    <style type=\"text/css\">body{background-color: #f1f1f1 ;font-family:\"Maven Pro\", sans-serif;text-align:center}img{border-radius:26px;box-shadow:0 0 3px #b8b8b8 ;height:auto;margin-top:15vh;max-width:100px;width:100%}h1{color:#575757 ;font-size:1.2em;margin-bottom:5vh}.btn{background-color:#00bed5 ;border:2px solid #00bed5 ;color:#fff;display:inline-block;font-weight:700;letter-spacing: 0.1em;max-width:200px;padding:10px;text-decoration:none;text-transform:uppercase;transition:all .3s ease-in-out;width:80%}p{color:#b8b8b8 ;margin-top:5vh;padding:0 20px}</style>\n" +
                "</head>\n" +
                "<body>\n" +
                "    <img id=\"app-img\">\n" +
                "    <h1 id=\"app-name\"></h1>\n" +
                "    <a href=\"https://apps.apple.com/app/id6745258320?mt=8\" class=\"btn\">Download App</a>\n" +
                "    <p>Please press the button to proceed to your app</p>\n" +
                "    <script>\n" +
                "window.location.href = 'https://apps.apple.com/app/id6745258320?mt\\u003D8';\n" +
                "    </script>\n" +
                "</body>\n" +
                "</html>\n";

        getWindowLocationReplaceUrl(tmpStr);
    }
}
